#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>

#include <regex.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

using namespace std;

/*双网卡时对应的顺序：
    默认写一个mac地址时，写eth1 ,核心板对应的网卡
*/
//#define  ETH0ADDR	 "eth1addr"   // eth0
#define  ETH0ADDR	 "ethaddr"    // eth1 ---核心板的PHY对应的
#define  ETH1ADDR      "MACAddress"   // eth0




#define setbit(x,y)  x|=(1<<y)  
#define clrbit(x,y)  x&=~(1<<y)  
#define reversebit(x,y)  x^=(1<<y)  
#define getbit(x,y)   ((x) >> (y)&1)

/***  2019-10-14
cmd   :  	0x0A  连接
status :    // 反馈
			bit0 ---mac0 状态, 1 正常， 0 错误
			bit1 ---mac1 状态, 1 正常， 0 错误

            0        0
            |        |
            mac1    mac0

            00  ---> err err      === 0x00
            01  ---> err ok       === 0x01
            10  ---> ok  err      === 0x02
            11  ---> ok ok        === 0x03

MacNum : MAC个数 0x01 --- 一个  0x02 --- 两个
MacaValue_a : MAC值---eth0  --->
MacaValue_b : MAC值---eth1

// test
eth1      Link encap:Ethernet  HWaddr 38:d5:47:00:25:29  ---> ethaddr
eth0      Link encap:Ethernet  HWaddr f4:4d:30:53:40:1d  ---> eth1addr

***/

/*mac struct */
struct _test_mac
{
    unsigned int cmd;
    unsigned int status;
	unsigned int isrdy;
    unsigned int MacNum;
    unsigned int MacaValue_a[6];  //eth1
    unsigned int MacaValue_b[6];  //eth0
};

struct _board_mac
{
    struct _test_mac  MacData_sd;
    struct _test_mac  MacData_rv;
};

struct _board_mac AL_Board_Mac;


/*
*brief 
*param: pattern,正则表达式字符串;value,the mac address.
*return value: if susscess,0 is returned,or 1 is returned on error.
*/
int ereg(char *pattern,const char *value)
{
    int r, cflags = 0;
    regmatch_t pm[10];
    const size_t nmatch = 10;
    regex_t reg;
 
    r = regcomp(&reg, pattern, cflags);
    if (r == 0)
    {
        r = regexec(&reg, value, nmatch, pm, cflags);
    }
    regfree(&reg);
 
    return r;
}
/*
*brief check whether the mac address is format-right
*param: the mac address
*return value: if susscess,0 is returned,or 1 is returned on error.
*/
int isValidMac(const char *macaddr)
{
    int r;
    char reg[1024] = {"^[a-f0-9A-F]\\([a-f0-9A-F]\\:[a-f0-9A-F]\\)\\{5\\}[a-f0-9A-F]$"};
    r = ereg(reg, macaddr);
    return r;
}


unsigned short sys_shell(const char *str_in)
{
    FILE   *stream;
    char   buf[500] = {0};
    //      string buf_str;
    stream = popen( str_in, "r" );
    fread( buf, sizeof(char), sizeof(buf),  stream);
    //      buf_str=buf;
    pclose( stream );
    return 0;
}
string sys_shell_ret(const char *str_in)
{
    FILE   *stream;
    char   buf[1024 * 8] = {0};
    string buf_str;
    stream = popen( str_in, "r" );
    fread( buf, sizeof(char), sizeof(buf),  stream);
    buf_str = buf;
    pclose( stream );
    return  buf_str;
}

string convert_str(unsigned int *src)
{
    string tmp;
    char buf[128];
    sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", *src, *(src + 1), *(src + 2), *(src + 3), *(src + 4), *(src + 5));
    tmp = buf;
    return tmp;
}

/*切割*/
vector<string> split(const string &str, const string &delim)
{
    vector<string> res;
    if("" == str) return res;
    //先将要切割的字符串从string类型转换为char*类型
    char *strs = new char[str.length() + 1] ;  
    strcpy(strs, str.c_str());

    char *d = new char[delim.length() + 1];
    strcpy(d, delim.c_str());

    char *p = strtok(strs, d);
    while(p)
    {
        string s = p; //分割得到的字符串转换为string类型
        res.push_back(s); //存入结果数组
        p = strtok(NULL, d);
    }
    return res;
}

unsigned int *convert_int(string src)
{
    unsigned int *ret = (unsigned int *)malloc( sizeof(unsigned int) * 6 );
    vector<string> tmp;
    tmp = split(src, ":");
    for(int i = 0; i < tmp.size(); i++)
    {
        ret[i] =  stoi(tmp[i], NULL, 16);
    }
    return ret;
}


/*
	ethaddr --- eth1
	eth1addr --- eth0
	read mac form env

	macno : 0  --->  eth0  --->  eth1addr
	macno : 1  --->  eth1  --->  ethaddr

	macno : 2  --->  eth0  --->  eth1addr
				--->  eth1  --->  ethaddr
*/
#if 0
string  read_mac_env(const char *_strin_macname)
{
    string ret_str;
    string mac_str,temp_str;
    char sys_cmd[128];
    sprintf(sys_cmd, "fw_printenv %s ", _strin_macname);
    ret_str = sys_shell_ret(sys_cmd);

    size_t cnt = 0;
    cnt = ret_str.find("=");
    if(cnt != string::npos)
    {
        temp_str = ret_str.substr(cnt + 1);
        mac_str  = temp_str.substr(0,temp_str.size()-1);   // 减去换行符
    }else{
		mac_str="none";
	}
    return mac_str;
}
#endif

/*for ya157c*/
//MACAddress=01:23:45:67:89:ab  11-27
string read_mac_env(const char *_strin_macname)
{
	string ret_str, mac_str, temp_str;
	char sys_cmd[128];
	char a[128];
	FILE *fp = NULL;
	int i;
	memset(sys_cmd,'0',128);

	const char *emmc_open = "mount -t ext4 /dev/mmcblk2p3 /mnt";
	sys_shell(emmc_open);
	sleep(1);
	//const char *mac_fd = "/mnt/etc/systemd/network/20-eth0.network";
	const char *mac_fd = "/mnt/MACaddress";
	fp = fopen(mac_fd, "r");
	if(fp == NULL){
		printf("network no file\n");
		sys_shell("umount /mnt");
		return "none";
	}
	
	while(!feof(fp))
	{
		fgets(a, sizeof(a), fp);
		if(feof(fp))
			printf("%s\n", a);
	}
	
	//memcpy(sys_cmd, a + 11, 17);
	memcpy(sys_cmd, a ,17);
	sys_cmd[17] = '\0';	
	fclose(fp);
	sys_shell("umount /mnt");
	sleep(1);
	return sys_cmd;
}

int write_mac_env(const char *_strin_macname, string _str_mac)
{
	int ret = 0;
	char sys_cmd[128] = {0};
	string ret_str;
	const char *value_mac;
	sys_shell("sed -i '$d' /home/MACaddress"); //del the last line
	value_mac = _str_mac.data();
	sprintf(sys_cmd, "echo %s > /home/MACaddress",value_mac);
	sys_shell(sys_cmd);

	const char *emmc_open = "mount -t ext4 /dev/mmcblk2p3 /mnt";
   	sys_shell(emmc_open);
	sleep(1);
	sys_shell("cp /home/MACaddress /mnt/");
	sys_shell("umount /mnt");
	sleep(1);	
	return 1;
	/*
	ret_str = read_mac_env(_strin_macname);
	if(ret_str == "")
		return -1;
	sleep(1);
	ret = ret_str.compare(_str_mac);
	if(ret == 0) return 1;
	else return -1;
	*/
}

/*
int write_mac_env(const char *_strin_macname, string _str_mac)
{
    string ret_str;
    int ret = 0;
    char sys_cmd[128];
    const char *value_mac;

    value_mac = _str_mac.data();
    const char *emmc_open = "echo 0 > /sys/class/block/mmcblk1boot0/force_ro";
    sys_shell(emmc_open);
    // wirite mac
    sprintf(sys_cmd, "fw_setenv %s %s ", _strin_macname, value_mac);
    sys_shell(sys_cmd);
    // read mac
    ret_str = read_mac_env(_strin_macname);
    const char *emmc_close = "echo 1 > /sys/class/block/mmcblk1boot0/force_ro";
    sys_shell(emmc_close);
    sleep(2);
    ret = ret_str.compare(_str_mac);
    if(ret == 0) return 1;
    else return -1;
    //	return ret_str;
}
*/

int main()
{
    string macvalue;
    string macvalue_tmp[2];
    unsigned int ret;

    // socket
    struct sockaddr_in serverAddr;

    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8000);
 //   serverAddr.sin_addr.s_addr = inet_addr("192.168.7.196");
	serverAddr.sin_addr.s_addr = inet_addr("192.168.30.202");


    int client = socket(AF_INET, SOCK_STREAM, 0);
    if (client == -1)
    {
        std::cout << "Error: socket" << std::endl;
        return 0;
    }

//
    int keepAlive = 1; // 开启keepalive属性
    int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
    int keepInterval = 5; // 探测时发包的时间间隔为5 秒
    int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

    // setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
    // setsockopt(client, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
    // setsockopt(client, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
    // setsockopt(client, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

    // connect
    do
    {
        if (connect(client, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
        {
            std::cout << "Error: connect" << std::endl;
        }
        else
        {
            std::cout << "Succeed: connect " << std::endl;
            break;
        };
        sleep(1);
    }
    while(1);

    /*
    	int recvTimeout = 30 * 1000;  //30s
    	int sendTimeout = 30 * 1000;  //30s
    	setsockopt(connSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&recvTimeout, sizeof(int));
    	setsockopt(connSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&sendTimeout, sizeof(int));
    */

	unsigned int *mac_read=(unsigned int *)malloc( sizeof(unsigned int) * 6 );
	macvalue_tmp[0] = read_mac_env(ETH1ADDR);
	printf("macvalue_tmp[0] = %s\n", macvalue_tmp[0].data());
	if(macvalue_tmp[0] == "none")
	{
		std::cout << "Error: no mac" << std::endl;
	}else{
		ret = isValidMac(macvalue_tmp[0].data());
		if(ret==0){  // 有mac0
			mac_read = convert_int(macvalue_tmp[0]);
			memcpy(AL_Board_Mac.MacData_sd.MacaValue_a,mac_read,sizeof(unsigned int)*6);
			AL_Board_Mac.MacData_sd.isrdy=1;
			std::cout << "eth0: mac is ok" << std::endl;
		}else
			std::cout << "yes: mac isvalid" << std::endl;
	}
	
	/*
	macvalue_tmp[1] = read_mac_env(ETH0ADDR);
	if(macvalue_tmp[0] == NULL)
	{
		std::cout << "Error: no mac2" << std::endl;
	}else{
        	ret = isValidMac(macvalue_tmp[1].data());
		if(ret==0){  // 有mac1
			mac_read = convert_int(macvalue_tmp[1]);
			memcpy(AL_Board_Mac.MacData_sd.MacaValue_b,mac_read,sizeof(unsigned int)*6);
			AL_Board_Mac.MacData_sd.isrdy=1;
		}
	}
	*/

	if(AL_Board_Mac.MacData_sd.isrdy==1){
		// 板子已经有MAC
		AL_Board_Mac.MacData_sd.cmd = 0x0B;
		send(client, &AL_Board_Mac.MacData_sd.cmd, sizeof(AL_Board_Mac), 0);
	}else{
	    // 板子没有MAC, 请扫MAC条形码
	    AL_Board_Mac.MacData_sd.cmd = 0x0A;
	    send(client, &AL_Board_Mac.MacData_sd.cmd, sizeof(AL_Board_Mac.MacData_sd.cmd), 0);
	}

    while (true)
    {
        int len = recv(client, &AL_Board_Mac.MacData_rv.cmd, sizeof(_board_mac), 0);
        std::cout << "recv mac value   1111111  = " << hex << len << std::endl;
        if(len > 0)
        {
            std::cout << "recv mac value ,cmd  0000000000000  = " << hex << AL_Board_Mac.MacData_rv.cmd << std::endl;
            if(AL_Board_Mac.MacData_rv.cmd == 0x1A)
            {
                // 接收到MAC value
                std::cout << "recv mac value, write value ==== " << hex << AL_Board_Mac.MacData_rv.MacaValue_a <<std::endl;
                // start wirte mac
                switch(AL_Board_Mac.MacData_rv.MacNum)
                {
                case 1:
			AL_Board_Mac.MacData_sd.MacNum=1;
                    	macvalue = convert_str(AL_Board_Mac.MacData_rv.MacaValue_a);
		     	printf("macvalue = %s", macvalue);
			
			if(write_mac_env(ETH1ADDR, macvalue)>0)
			{
				printf("status1 = %d\n", AL_Board_Mac.MacData_sd.status);
                        	setbit(AL_Board_Mac.MacData_sd.status,0); // 设置1 
			}
			else
			{
				printf("status = %d\n", AL_Board_Mac.MacData_sd.status);
                        	clrbit(AL_Board_Mac.MacData_sd.status,0); // 设置0
			}		
			memcpy(AL_Board_Mac.MacData_sd.MacaValue_a,AL_Board_Mac.MacData_rv.MacaValue_a,sizeof(unsigned int)*6);
                    break;
                case 2:
			AL_Board_Mac.MacData_sd.MacNum=2;
                    	macvalue = convert_str(AL_Board_Mac.MacData_rv.MacaValue_a);
		    	printf("macvalue = %s", macvalue);
                    	
			if(write_mac_env(ETH1ADDR, macvalue)>0)
				setbit(AL_Board_Mac.MacData_sd.status,0); 
			else
				clrbit(AL_Board_Mac.MacData_sd.status,0); 

                    	macvalue = convert_str(AL_Board_Mac.MacData_rv.MacaValue_a);
                    	
			if(write_mac_env(ETH0ADDR, macvalue)>0)
				setbit(AL_Board_Mac.MacData_sd.status,1); 
			else
				clrbit(AL_Board_Mac.MacData_sd.status,1); 
					
			memcpy(AL_Board_Mac.MacData_sd.MacaValue_a,AL_Board_Mac.MacData_rv.MacaValue_a,sizeof(unsigned int)*6);
			memcpy(AL_Board_Mac.MacData_sd.MacaValue_b,AL_Board_Mac.MacData_rv.MacaValue_b,sizeof(unsigned int)*6);
                    break;
                default:
                    break;
                }
                // 反馈信息
                std::cout << "write  777777 =  " <<  AL_Board_Mac.MacData_sd.status  << std::endl;
                AL_Board_Mac.MacData_sd.cmd = 0x1B;
                send(client, &AL_Board_Mac.MacData_sd.cmd, sizeof(AL_Board_Mac), 0);
				
            }
            else if(AL_Board_Mac.MacData_rv.cmd == 0xCC)
            {
                std::cout << "heart  =  "  << std::endl;
                AL_Board_Mac.MacData_sd.cmd = 0xCC;
                send(client, &AL_Board_Mac.MacData_sd.cmd, sizeof(AL_Board_Mac.MacData_sd.cmd), 0);
            }
            
        }else if (len==0)
        {
            // /* code */
            // // 连接断开
            // int client = socket(AF_INET, SOCK_STREAM, 0);
            // if (client == -1)
            // {
            //     std::cout << "Error: socket" << std::endl;
            //     return 0;
            // }

            // if (connect(client, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
            // {
            //     std::cout << "Error: connect" << std::endl;
            // }
            // else
            // {
            //     std::cout << "Succeed: connect " << std::endl;
            // };
            // usleep(5000);

        }

        // sleep(1);
        // std::cout << "heart  =  "  << std::endl;
        // AL_Board_Mac.MacData_sd.cmd = 0xCC;
        // send(client, &AL_Board_Mac.MacData_sd.cmd, sizeof(AL_Board_Mac.MacData_sd.cmd), 0);
        std::cout << "threading .... " << std::endl;
        // sleep(1);
        usleep(50000);
    }
    close(client);
    return 0;
}
